package playgame;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 * Controls all things GUI.
 * 
 * Handles the connection of the mospart of the objects for bomberman, in addition it handles logic for moving objects, like player.
 * This class also administers the threads. 
 * 
 * @author Bomberman Crew 20(C)09
 * 
 */
@SuppressWarnings("serial")
public class GUIen extends DrawLevel2 implements Runnable {
	Keyboard keyboard = new Keyboard();
	JFrame frame;
	DrawLevel2 level = new DrawLevel2();
	boolean running;
	
	int width;
	int height;
	int xpos;
	int ypos;
	
	Thread t;
	Thread sound;

	SoundPlayer bgmusic;
	
	BufferedImage bombImage = loadImage("bomb.png");
	BufferedImage playerImage = loadImage("player40.gif");
	BufferedImage player2Image = loadImage("player402.gif");
	BufferedImage wallImage = loadImage("wall.gif");
	BufferedImage fireImg = loadImage("bang.gif");
	
	/**
	 * Creates a <code>JFrame</code> with the following parameters
	 * 
	 * @param text
	 *            The string to display in the JLabel
	 * @param width
	 *            The int width of the frame to create
	 * @param height
	 *            The int height of the frame to create
	 * @param xpos
	 *            The x int coordinate for the position of the frame
	 * @param ypos
	 *            The y int coordinate for the position of the frame
	 */
	public GUIen(int width, int height, int xpos, int ypos) {
		runMenu(width, height, xpos, ypos);
		this.width = width;
		this.height = height;
		this.xpos = xpos;
		this.ypos = ypos;
		
	}
	public void runMenu(int width, int height, int xpos, int ypos) {
		frame = new JFrame("Bomberman");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setBounds(xpos, ypos, width, height);
		frame.setLayout(new BorderLayout());
        frame.setBackground(Color.BLACK);
        frame.setResizable(false);
        

		 final ImageIcon load = new ImageIcon("resources/bomber-icon.png");
	        final JLabel imglabel = new JLabel(load);
	        
	        final JPanel panel = new JPanel();
	        
	        frame.add(panel, BorderLayout.CENTER);
	        
	        panel.add(imglabel);
	        
	        final ImageIcon rollover = new ImageIcon("resources/bomber-icon-h.png");
	        
	        imglabel.addMouseListener(new MouseListener() {
			
				public void mouseReleased(MouseEvent e) {
			
				}
			
				public void mousePressed(MouseEvent e) {
			
				}
			
				public void mouseExited(MouseEvent e) {
					imglabel.setIcon(load);
			
				}
			
				public void mouseEntered(MouseEvent e) {
					imglabel.setIcon(rollover);
			
				}
			
				public void mouseClicked(MouseEvent e) {
					frame.setVisible(false);
					frame.dispose();
					runGame(766, 545, 300, 100);
				}
			});
	        frame.setVisible(true);
		
	}
	
	public void runGame(int width, int height, int xpos, int ypos) {
		frame = new JFrame("Bomberman");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setBounds(xpos, ypos, width, height);
		frame.setResizable(false);
		
		
		GameObject wall = new GameObject(wallImage);
		addWalls(wall, 18, 12);

		GameObject player1 = new Player(playerImage);
		((Player)player1).setControls(87, 83, 65, 68, 88);
		((Player)player1).setSpeed(35);
		((Player)player1).setName("Player 1");
		((Player)player1).setId(1);
		level.addPlayer(player1);

		GameObject player2 = new Player(player2Image);
		((Player)player2).setControls(73, 75, 74, 76, 78);
		((Player)player2).setSpeed(35);
		((Player)player2).setName("Player 2");
		((Player)player2).setId(2);
		((MovingGameObject)player2).setX(720);
		((MovingGameObject)player2).setY(480);
		level.addPlayer(player2);
		
		frame.addKeyListener(keyboard);
		frame.setContentPane(level);
		
		frame.setVisible(true);
		Random random = new Random();
		int songNr = random.nextInt(4) + 1;
		bgmusic = new SoundPlayer(Integer.toString(songNr));
				
		
		sound = new Thread(bgmusic);
		sound.start();
		
		t = new Thread(this);
		t.start();
	}
	
	public void doMove(GameObject player){
		Player p;
		p = ((Player)player);
		if (keyboard.keyDown(p.up)) {
			if (legalMove(player, "up") && legalUp(player))
				((MovingGameObject)player).move(0,-1*(5 + p.getSpeed()));
		}
		if (keyboard.keyDown(p.left)){
			if (legalMove(player, "left") && legalLeft(player))
				((MovingGameObject)player).move(-1*(5 + p.getSpeed()),0);
		}
		if (keyboard.keyDown(p.down)){
			if (legalMove(player, "down") && legalDown(player))
				((MovingGameObject)player).move(0,1*(5 + p.getSpeed()));
		}
		if (keyboard.keyDown(p.right)){
			if (legalMove(player, "right") && legalRight(player))
				((MovingGameObject)player).move(1*(5 + p.getSpeed()),0);
		}
		if (keyboard.keyDown(p.plant)){
			plantBomb(player);
		}
	}

	/**
	 * Add walls to the ArrayList in the DrawLevel2 (level) object
	 * 
	 * @param wall
	 *            - the GameObject representing the unmoveable walls
	 * @param x
	 *            - the int representing the position on the x-axis
	 * @param y
	 *            - the int representing the position on the y-axis
	 */
	public void addWalls(GameObject wall, int x, int y) {
		for (int i = 0; i <= x; i++)
			for (int j = 0; j <= y; j++) {
				level.walls.add(wall);
			}

	}

	
	public boolean legalMove(GameObject player, String move) {
		return boundaryCheck(player, move); // && (crashTestX(player) || crashTestX(player));
	}

	/**
	 * Checks if the move is out of bounds
	 * 
	 * @param player
	 *            - the Player object representing a player
	 * @param move
	 *            - the String representing what type of move
	 *            (up,down,left,right)
	 * @return - returns a boolean, true if the move is legal etc.
	 */
	boolean boundaryCheck(GameObject player, String move){
		if (move == "up") {
			if (!(((MovingGameObject) player).getY() > 0))
				return false;

			return true;
		}

		else if (move == "right") {
			if (!(((MovingGameObject) player).getX() < 720))
				return false;

			return true;
		}

		else if (move == "down") {
			if (!(((MovingGameObject) player).getY() < 480))
				return false;

			return true;
		} else if (move == "left") {
			if (!(((MovingGameObject) player).getX() > 0))
				return false;

			return true;
		}
		return false;
	}

	/**
	 * Checks if a Player Object crashes in an unmoveable wall. The map is made like a grid where each square is 40x40 pixels
	 * the player is only allowed to move on the 1, 3, 5, etc.. row and colum. These methods then check where the player is
	 * located and then only allowing the player to move in a the direction that does not bring the player into a "grid-field" 
	 * that cointains a wall.
	 * 
	 * @param player
	 *            - the Player Object we want to check
	 * @return - returns true/false
	 */
	
	
	public boolean legalRight(GameObject player) {
		int x = ((MovingGameObject) player).getY();
		int h = player.getHeight();
		for (int i = 0; i < 20; i++){
			if ( (x >= (80 * i) ) && ((x+h) <= (40 + (80 * i)))){
				return true;
			}
		}
		return false;
	}
	
	public boolean legalUp(GameObject player) {
		int x = ((MovingGameObject) player).getX();
		int h = player.getHeight();
		for (int i = 0; i < 20; i++){
			if ( (x >= (80 * i) ) && ((x+h) <= (40 + (80 * i)))){
				return true;
			}
		}
		return false;
	}
	
	public boolean legalDown(GameObject player) {
		int x = ((MovingGameObject) player).getX();
		int h = player.getHeight();
		for (int i = 0; i < 20; i++){
			if ( (x >= (80 * i) ) && ((x+h) <= (40 + (80 * i)))){
				return true;
			}
		}
		return false;
	}
	
	public boolean legalLeft(GameObject player) {
		int x = ((MovingGameObject) player).getY();
		int h = player.getHeight();
		for (int i = 0; i < 20; i++){
			if ( (x >= (80 * i) ) && ((x+h) <= (40 + (80 * i)))){
				return true;
			}
		}
		return false;
	}
	

	/**
	 * Checks if a Player Object crashes in an unmoveable wall
	 * 
	 * @param player
	 *            - the Player Object we want to check
	 * @return - returns true/false
	 */
	public boolean crashTestY(GameObject player) {
		int x = ((MovingGameObject) player).getY();
		int b = player.getHeight();

		for (int i = 0; i < 20; i++) {
			if (x >= 80 * i && x + b <= ((80 * i) + 40))
				return true;
		}
		return false;
	}

	/**
	 * Plants the bomb from a Player and adds the Player as the Owner of the
	 * bomb
	 * 
	 * @param player
	 *            - the Player Object.
	 */
	public void plantBomb(GameObject player) {
		if (((Player) player).getBombs() > 0) {
			GameObject bomb = new Bomb(bombImage);
			((MovingGameObject) bomb).setX(((MovingGameObject) player).getX());
			((MovingGameObject) bomb).setY(((MovingGameObject) player).getY());
			if (legalLeft(bomb) && legalUp(bomb)){
				
				((Bomb) bomb).setType(1);
			}
			else if (!legalDown(bomb)){
				((Bomb) bomb).setType(2);
			}
			else{
				((Bomb) bomb).setType(3);
			}
			level.addBomb(bomb);
			((Bomb) bomb).setOwner((Player) player);
			((Player) player).removeBomb();
			
			
			
		}
	}

	/**
	 * Checks if the bombs has exploded
	 */
	public void explode() {
		for (int i = 0; i < level.bombs.size(); i++) {
			if (!((Bomb) level.bombs.get(i)).getStatus()) {
				int bType = ((Bomb) level.bombs.get(i)).getType();
				int xCord = ((MovingGameObject) level.bombs.get(i)).getX();
				int yCord = ((MovingGameObject) level.bombs.get(i)).getY();
				((Bomb) level.bombs.get(i)).getOwner().addBomb();
				level.bombs.remove(i);
				System.out.println("Bombsmoke! Don't breath this!");
				switch (bType) {
				case 1:
					for (int j = -2; j <= 2; j++) {
						level.addFire(new Fire(fireImg,xCord+(j*40), yCord));
						level.addFire(new Fire(fireImg,xCord, yCord+(j*40)));
					}
					break;
				case 2: 
					for (int j = -2; j <= 2; j++) {
						level.addFire(new Fire(fireImg,xCord+(j*40), yCord));
					}
					break;
				case 3:
					for (int j = -2; j <= 2; j++) {
						level.addFire(new Fire(fireImg,xCord, yCord+(j*40)));
					}
					break;
				}
							

			}
		}
		for (int i = 0; i < level.fires.size(); i++) {
			for (int j = 0; j < level.players.size(); j++) {
				int pX = ((MovingGameObject) level.getPlayer(j)).getX();
				int pY = ((MovingGameObject) level.getPlayer(j)).getY();
				int fX = level.getFires(i).getCordX();
				int fY = level.getFires(i).getCordY();
				if (pX == fX && pY == fY){
					level.removePlayer(level.getPlayer(j));
				}
			}
			if (!((Fire) level.fires.get(i)).getStatus()){
				level.fires.remove(i);
			}
		}
	}
	
	public void checkPlayer(){
		switch (level.players.size()) {
		case 0:
			System.out.println("It's a fuckin' draw!");
			level.setWinner(0);
			level.setEndGame(true);
			stop();
			
			break;
		case 1:
			System.out.println(((Player) level.getPlayer(0)).getName() + " wins!");
			level.setWinner(((Player) level.getPlayer(0)).getId());
			level.removePlayer(level.getPlayer(0));
			level.setEndGame(true);
			stop();
			break;
		}
	}
	
	

	public void run() {
		running = true;
		while (running) {
			frame.setContentPane(level);
			explode();
			checkPlayer();
			keyboard.poll();
			for (int i = 0; i < level.players.size(); i++) {
				doMove(level.getPlayer(i));
			}
			try {
				Thread.sleep(200);
			} catch (InterruptedException ie) {

			}
		}
		while (level.isEndGame()){
			GameObject wall = new GameObject(wallImage);
			level.addEndWall(wall);
			
			frame.setContentPane(level);
			if (level.endWalls.size() == 280){
				level.setEndGame(false);
				System.exit(0);
			}
			
			try {
				
				Thread.sleep(17);
			}
			catch (InterruptedException e) {
				// Handle exception
			}
		}
		cleanFrame();
	}

	public void stop() {
		running = false;
		bgmusic.stop();
		bgmusic.stopSound();
	}
	
	public void cleanFrame(){
		frame.setVisible(false);
		frame.dispose();
		runMenu(width, height, xpos, ypos);
		
	}

}
